/*
 * demo.hpp
 *
 *  Created on: 2021年10月18日
 *      Author: guyadong
 */

#ifndef EXAMPLES_DEMO_HPP_
#define EXAMPLES_DEMO_HPP_
#include <dtalk/dtalk_engine.h>
namespace dtalk
{
	struct DemoMenu;
	using demo_menu_ptr = std::shared_ptr<DemoMenu>;
	/** 演示菜单定义 */
	struct DemoMenu : public RootMenu
	{		
		simplemq::base_client_params_ptr clientParam;
		dev_info_ptr devInfo;
		DemoMenu(const simplemq::base_client_params_ptr &clientParam = nullptr, const dev_info_ptr &devInfo = nullptr) : clientParam(clientParam), devInfo(devInfo){}
		virtual ~DemoMenu() = default;
		virtual void init() override
		{
			RootMenu::init();
			auto mac = devInfo ? devInfo->getMacAsString() : "00:00:00:00:00:00";
			auto ip = devInfo ? devInfo->getIpAsString() : "127.0.0.1";
			auto password = devInfo ? devInfo->getPassword() : "";
			auto device = make_item_shared<MenuItem>("device", "设备(device)");
			device->addChilds({
				make_option_shared<StringOption>("name", "设备名称(name)"),
				make_option_shared<StringOption>("sn", "设备序列号码(sn)")->asValue("001122334455"),
				make_option_shared<IPv4Option>("IP", "IP地址(IP)")->asValue(ip)->setField(_jf_readOnly,true),
				make_option_shared<MACOption>("mac","物理地址(mac)")->asValue(mac)->setField(_jf_readOnly,true),
				make_option_shared<StringOption>("gps", "位置(GPS)")->setField(_jf_readOnly, true),
				make_option_shared<PasswordOption>("password","连接密码(password)")->asValue(password)});
			item_ptr_type mq;
			if (clientParam)
			{
				if (clientParam->schema == simplemq::MQTT_SCHEMA)
				{
					mq = make_item_shared<MenuItem>("mq","Message Queue 服务(mq)");
					mq->addChilds({
						make_option_shared<StringOption>("type","消息系统类型(type)", "", "", item_features::F_READONLY)->setValue("MQTT"),
						make_option_shared<StringOption>("host", "主机(host)")->asValue(clientParam->host),
						make_option_shared<IntOption>("port", "端口(port)")->setValue(clientParam->port),
						make_option_shared<StringOption>("username", "用户(username)")->asValue(clientParam->username),
						make_option_shared<PasswordOption>("password", "连接密码(password)")->asValue(clientParam->password),
					});
				}
				else if (clientParam->schema == simplemq::REDIS_SCHEMA)
				{
					mq = make_item_shared<MenuItem>("mq", "Message Queue 服务(mq)");
					mq->addChilds({
						make_option_shared<StringOption>("type","消息系统类型(type)", "", "", item_features::F_READONLY)->setValue("REDIS"),
						make_option_shared<StringOption>("host", "主机(host)")->asValue(clientParam->host),
						make_option_shared<IntOption>("port", "端口(port)")->setValue(clientParam->port),
						make_option_shared<PasswordOption>("password", "连接密码(password)")->asValue("password"),
					});
				}
				else {
					throw std::invalid_argument(gdface::string_utils::format("UNSUPPORTED message queue schema:%s port:%d", clientParam->schema.c_str(), clientParam->port));
				}
			}
			auto test = make_item_shared<MenuItem>("test", "类型测试(test)");

			auto now = std::chrono::system_clock::now();
			auto  mills = std::chrono::time_point_cast<std::chrono::milliseconds>(now);
			test->addChilds({
				make_option_shared<DateOption>("date", "日期测试(date)")->setValue(mills),
				make_option_shared<BoolOption>("bool", "BOOL测试(bool)")->setValue(true),
				make_option_shared<IPv4Option>("ipv4", "IPV4测试(ipv4)")->asValue("127.0.0.1"),
				make_option_shared<MACOption>("mac", "MAC测试(mac)")->asValue("22:35:ff:e0:3f:ab"),
				make_option_shared<SwitchOption>("switch","SWITCH测试(switch)")->as<SwitchOption>()
					->addOption(0.0f,"zero")
					->addOption(0.5f, "half")
					->addOption(1.0f, "full"),
				make_option_shared<CheckOption>("check","CHECK测试(check)")->as<CheckOption>()
					->addOption("中国 (CHINA)", "zero")
					->addOption("俄罗斯的 (RUSSIA)", "half")
					->addOption("美国 (USA)", "full"),
				make_option_shared<EmailOption>("email", "EMAIL测试(email)")->asValue("my@hello.com"),
				make_option_shared<MphoneOption>("mphone", "移动电话号码测试(mphone)")->asValue("13611426411"),
				make_option_shared<IdnumOption>("idnum", "身份证号码的测试 (idnum)")->asValue("320113199001133483"),
				make_option_shared<IntOption>("integer", "数字测试(integer)")->setValue(0),
				make_option_shared<UrlOption>("url", "URL测试(url)")->asValue("https://gitee.com/l0km/dtalk.git"),
				make_option_shared<ImageOption>("image", "图像测试(image)")
			});

			if (mq) {
				addChilds({ mq });
			}
			addChilds({ device, test });
		}
	};

	/**
	 * dtalk 引擎演示
	 */
	struct Demo {
		/** 设备物理地址 */
		std::string devMac;
		/** 消息订阅实例 */
		simplemq::subscriber_ptr subscriber;
		/** 连接器实例 */
		dtalk::engine::sample_onnector_ptr connAdapter;
		/** DemoMenu 实例 */
		menu_ptr_type root;
		virtual ~Demo() = default;

		//************************************
		// 构造函数
		// @param    simplemq::BaseClientManager * cmgr 提供消息系统(REDIS/MQTT)连接实例
		// @param    const simplemq::base_client_params_ptr & config 连接参数
		// @param    const dev_info_ptr & devInfo 设备信息实例
		//************************************
		Demo(simplemq::BaseClientManager* cmgr, const simplemq::base_client_params_ptr &config, const dev_info_ptr &devInfo) {
			throw_if_null(cmgr);
			throw_if_null(config);
			throw_if_null(devInfo);
			std::cout << gdface::log::sample_format("Device talk {} Demo starting", cmgr->getImplType());
			std::cout << gdface::log::sample_format("use config = {}", config->to_string());
			/** 获取消息订阅实例 */
			subscriber = cmgr->getSubscriber(config);
			/** 获取消息发布实例 */
			auto publisher = cmgr->getPublisher(config);
			/** 如果未提供设备信息实例则使用默认实例 */
			dev_info_ptr dip = devInfo ? devInfo : std::make_shared<DefaultDevInfoProvider>();
			/** 创建演示菜单 */
			root = make_menu_shared<DemoMenu>(config, devInfo);
			//SAMPLE_LOG("menu {}",root->toJson().dump(4));
			devMac = devInfo->getMacAsString();
			/** 创建连接器实例,用于订阅连接频道,接收连接请求 */
			connAdapter = std::make_shared<dtalk::engine::SampleConnector>(publisher, subscriber)
				->setSelfMac(devMac) /** 指定当前设备的物理地址 */				
				->setItemAdapter(std::make_shared<dtalk::engine::ItemEngineMqImpl>(publisher)->setRoot(root))/** 指定菜单引擎 */
				->setDeviceInfo(dip)/** 指定设备信息实例 */;
		}
		Demo(simplemq::BaseClientManager& cmgr, const simplemq::base_client_params_ptr &config, const dev_info_ptr &devInfo)
			:Demo(&cmgr, config, devInfo) {}
		Demo(const simplemq::base_cmgr_ptr& cmgr, const simplemq::base_client_params_ptr &config, const dev_info_ptr &devInfo)
			:Demo(cmgr.get(), config, devInfo) {}
		/**
		 * 启动连接
		 */
		void start() {
			std::cout << gdface::log::sample_format("DEVICE MAC address: {}", devMac);
			/** 连接频道 */
			std::string connchname = getConnChannel(devMac);
			simplemq::Channel connch(connchname, connAdapter);
			/** 将连接器connAdapter注册连接频道,开始接收连接请求 */
			subscriber->_register({ connch });
			std::cout << gdface::log::sample_format("Connect channel registered : {}", connchname);
			std::cout << gdface::log::sample_format("Press 'Ctrl-C' for quit");
		}
	};
} /* namespace dtalk */

#endif /* EXAMPLES_DEMO_HPP_ */
